#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：api_auto_upgrade 
@File    ：excel_handle.py
@IDE     ：PyCharm 
@Author  ：future76
@Date    ：2024/5/17 9:16 
@Desc    ：excel文件操作
"""
# 标准库导入
from typing import Union, Optional, List
# 第三方库导入
import openpyxl
# 本地应用/模块导入
from utils.files_utils.files_handle import get_files, get_file_path


class ExcelHandle:
    """excel文件操作"""

    @classmethod
    def read_excel(cls, file_path, sheet_name, min_row=1, switch=False):
        """
        读取Excel文件，只支持 .xlsx文件

        :param file_path: 读取的文件路径
        :param sheet_name: 读取的sheet表
        :param min_row: 读取的起始行，默认为1
        :param switch: 如果为True,文档中的is_true启用
        :return: 读取excel文件数据, [{},{}]
        """
        # 打开现有的Excel文件或创建新的文件
        try:
            #  正常情况下直接打开
            workbook = openpyxl.load_workbook(file_path)
        except FileNotFoundError:
            print(f"文件 {file_path} 未找到。")
            workbook = openpyxl.Workbook()
        except Exception as e :
            print(f"excel文件格式不正确{e}")
            workbook = openpyxl.Workbook()

        # 选择或创建指定的工作表
        if sheet_name in workbook.sheetnames:
            #判断有没有对应的sheet_name ，有的话把对应的数据加载出来
            worksheet = workbook[sheet_name]
        else:
            # 没有,新建
            worksheet = workbook.create_sheet(sheet_name)

        # 获取列名 --- 把第2行的数据拿出来作为key值
        # TODO 注意优化,暂时不调整
        headers = [cell.value for cell in worksheet[2]]

        # 将数据存储为字典,并且放在data当中
        data = []  # 所有的数据

        # 因为excel文件有两个列表行，所以数据从第三行开始
        for row in worksheet.iter_rows(min_row=min_row, values_only=True):
            # 把所有的数据直接加进去
            #  当 is_true == True才应该加进去，判断是否执行用例
            new_data = dict(zip(headers, row))
            if switch:
                try:
                    if new_data["is_true"] is True:
                        data.append(new_data)
                except KeyError as e:
                    print(f"缺少字段{e}")
            else:
                data.append(new_data)
        workbook.close()
        # 所有的数据
        return data

    @classmethod
    def write_excel(cls, file_path, sheet_name, row, column, value):
        """
        写入excel文件

        :param file_path: 文件的绝对路径
        :param sheet_name: 对应的sheet表
        :param row: 指定行
        :param column: 指定列
        :param value: 修改成指定的值
        """
        # 打开现有的Excel文件或创建新的文件
        try:
            workbook = openpyxl.load_workbook(file_path)
        except FileNotFoundError:
            workbook = openpyxl.Workbook()

        # 选择或创建指定的工作表
        if sheet_name in workbook.sheetnames:
            worksheet = workbook[sheet_name]
        else:
            worksheet = workbook.create_sheet(sheet_name)

        # 写入数据到指定行和列
        worksheet.cell(row=row, column=column).value = value

        # 保存修改后的文件--- 所以执行过程当中excel是要关闭的状态
        workbook.save(file_path)

    @classmethod
    def read_multifile_data(cls, target=None, appoint_file: Optional[Union[str, List[str]]] = None, sheet_name=None, min_row = 1, switch=False):
        """
        读取多个excel文件的数据

        :param target: 文件夹路径
        :param appoint_file: 指定文件,如果指定多个文件，请使用列表传参
        :param sheet_name: 读取的sheet表
        :param min_row: 读取的起始行
        :param switch: 如果为True,文档中的is_true启用
        :return: 读取的数据，数据格式是格式{"文件名1": [{}, {}, ...],"文件名2": [{}, {}, ...], ...}
        """
        if appoint_file is None and target is None:
            raise ValueError("必须提供'target'或'appoint_file'。")
        file_data = {}
        # 如果指定文件
        if appoint_file:
            if isinstance(appoint_file, list):
                file_names = appoint_file
            else:
                file_names = [appoint_file]
            for file in file_names:
                file = get_file_path(file, start_directory=target)
                file_data[file] = cls.read_excel(file_path=file, sheet_name=sheet_name, min_row=min_row, switch=switch)
        # 否则就读取指定的文件夹下的全部文件
        else:
            files = get_files(target)
            for file in files:
                file_data[file] = cls.read_excel(file_path=file, sheet_name=sheet_name, min_row=min_row, switch=switch)
        return file_data

    @classmethod
    def write_multifile_data(cls, target=None, appoint_file: Optional[Union[str, List[str]]] = None,
                             sheet_name="Sheet1", row=None, column=None, value=None):
        """
        写入多个excel文件的数据

        :param target: 文件夹路径
        :param appoint_file: 指定文件,如果指定多个文件，请使用列表传参
        :param sheet_name: Excel文件中的工作表名称。
        :param row: 要写入数据的行号（从1开始，如果为None，则在最后写入）。
        :param column: 要写入数据的列名或列索引
        :param value: 要写入的数据值。
        """
        if appoint_file is None and target is None:
            raise ValueError("必须提供'target'或'appoint_file'。")
        # 如果指定文件
        if appoint_file:
            if isinstance(appoint_file,list):
                file_names = appoint_file
            else:
                file_names = [appoint_file]
            for file in file_names:
                file = get_file_path(file, start_directory=target)
                cls.write_excel(file_path=file, sheet_name=sheet_name,
                                row=row, column=column, value=value)
        # 否则就读取指定的文件夹下的全部文件
        else:
            files = get_files(target)
            for file in files:
                cls.write_excel(file_path=file, sheet_name=sheet_name,
                                                      row=row, column=column, value=value)

    # TODO 注意优化
    @classmethod
    def multifile_excel(cls, target=None, appoint_file=None, sheet_name="Sheet1",
                        row=None, column=None, value=None,min_row = 3, switch = True, mode="r"):
        """
        处理多个Excel文件的读取和写入操作

        :param target_dir: 包含Excel文件的目录路径。
        :param appoint_file: 指定要操作的文件名（如果为None，则处理目录下的所有文件）。
        :param sheet_name: Excel文件中的工作表名称。
        :param row: 要写入数据的行号（从1开始，如果为None，则在最后写入）。
        :param column: 要写入数据的列名或列索引
        :param value: 要写入的数据值。
        :param mode: 操作模式，"r" 表示读取，"w" 表示写入（如果文件已存在则覆盖）。
        :return: 读取模式下返回工作表数据（这里简化为返回工作表对象列表），写入模式下返回None。
        """
        if mode not in ("r", "w"):
            raise ValueError("读模式必须为“r”，写模式必须为“w”。")
        if mode == "r":
            return cls.read_multifile_data(target, appoint_file, sheet_name, min_row, switch)
        elif mode == "w":
            if row is None or column is None or value is None:
                raise ValueError("写入时，必须指定行、列和值。")
            cls.write_multifile_data(target, appoint_file, sheet_name, row, column, value)

    @classmethod
    def field_location(cls, data, key):
        """
        根据字段名，定位字段在用例数据中的行和列

        :param data: 用例数据 {}
        :param key: 字段名
        :return: 行，列
        """
        for col, keys in enumerate(data):
            if keys == key:
                row = data["id"]+2
                col = col+1
                return row, col


if __name__ == '__main__':
    pass
